package pgpchat.pgp;

import java.io.UnsupportedEncodingException;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import pgpframework.Message.PGPAuthMessage;
import pgpframework.Message.PGPConfMessage;
import pgpframework.Message.PGPMessage;
import pgpframework.authentication.ApplySignatureActor;
import pgpframework.authentication.VerifySignatureActor;
import pgpframework.authentication.algorithm.SignatureEnum;
import pgpframework.authentication.key.GeneratorKeyPair;
import pgpframework.crypto.algorithm.CipherAlgorithmEnum;
import pgpframework.crypto.engine.SymetricCipherEngine;
import pgpframework.hash.SHAHashGenerator;
import pgpframework.util.CryptoUtil;

public class PGPActor {

	private final PublicKey publicKey;
	private final PrivateKey privateKey;
	private PublicKey receiverPubKey;
	SymetricCipherEngine cipher;

	public PGPActor() {
		KeyPair par = GeneratorKeyPair.generate("chaves");
		this.privateKey = par.getPrivate();
		this.publicKey = par.getPublic();
		cipher = new SymetricCipherEngine();
	}

	public PGPMessage gerarMensagemPGP(String msg) {
		return new PGPMessage((this.gerarMensagemConfidencialidade(msg)), this.gerarMensagemAutenticacao(msg));

	}

	public PGPAuthMessage gerarMensagemAutenticacao(String msg) {
		String msgHash = generateMsgHash(msg);
		byte[] assinatura = assinaMensagem(msgHash);
		return new PGPAuthMessage(msg, msgHash, assinatura);

	}

	private byte[] assinaMensagem(String msg) {
		ApplySignatureActor actor = new ApplySignatureActor();
		return actor.doApllySginature(this.privateKey, msg);
	}

	public PGPConfMessage gerarMensagemConfidencialidade(String msg) {

		SymetricCipherEngine cipher = new SymetricCipherEngine();
		SecretKey key = CryptoUtil.generate128SecretKey();
		byte[] msgCifrada = cipher.encryptData(msg.getBytes(), key, CipherAlgorithmEnum.AES);
		byte[] pubKeyCifrada = cipher.encryptData(key.getEncoded(), this.receiverPubKey, SignatureEnum.RSA_ECB_PKCS1Padding);
		return new PGPConfMessage(msgCifrada, pubKeyCifrada);
	}

	public void setReceiverPubKey(PublicKey key) {
		this.receiverPubKey = key;
	}

	public void receiveAuthMessage(PGPAuthMessage pgpMsg) {

		if (verificaAssinatura(pgpMsg.getAssinatura(), receiverPubKey) && verificaHash(pgpMsg.getMsg(), pgpMsg.getMsgHash())) {
			System.out.println("Receiver: mensaagem recebida foi: " + pgpMsg.getMsg());

		} else {
			System.out.println("Receiver: erro ao ler a menssagem");
		}
	}

	public String receiveConfMessage(PGPConfMessage pgpMsg) {
		byte[] secretkey = desencriptaChaveSecreta(pgpMsg.get_secretkey_cipher_with_PubKey());
		byte[] msg = desencriptaMsg(secretkey, pgpMsg.get_msg_cipher_with_secrectkey());
		try {
			String value = new String(msg, "UTF-8");
			System.out.println("Receiver: Menssagem recebida foi : " + value);
			return value;
		} catch (UnsupportedEncodingException ex) {
			System.out.println("Erro ao escrever msg");
			return null;
		}
	}

	private byte[] desencriptaChaveSecreta(byte[] chaveCript) {

		byte[] result = null;
		try {
			result = cipher.decryptData(chaveCript, this.privateKey, SignatureEnum.RSA_ECB_PKCS1Padding);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("erro ao desencriptar com a chave privada");
		}
		return result;
	}

	private byte[] desencriptaMsg(byte[] chaveCript, byte[] msgCript) {
		SecretKeySpec secretKeySpecDecrypted = new SecretKeySpec(chaveCript, "AES");
		byte[] result = null;
		try {
			result = this.cipher.decryptData(msgCript, secretKeySpecDecrypted, CipherAlgorithmEnum.AES);
		} catch (Exception e) {
			System.out.println("erro ao desencriptar com a chave privada");
		}
		return result;

	}

	private boolean verificaHash(String msg, String msgHash) {
		if (msgHash.equals(generateMsgHash(msg))) {
			System.out.println("Receiver: hash verificado");
			return true;
		}

		System.out.println("Receiver: hash nao verificado");
		return false;
	}

	private String generateMsgHash(String msg) {
		SHAHashGenerator hashgen = new SHAHashGenerator();
		return hashgen.generateStringHash(msg);

	}

	private boolean verificaAssinatura(byte[] assinatura, PublicKey publicKey) {
		VerifySignatureActor actor = new VerifySignatureActor();

		if (actor.doVerifySignature(publicKey, assinatura)) {
			System.out.println("Receiver: Assinatura verificada");
			return true;
		}

		System.out.println("Receiver: Assinatura não verificada");
		return false;
	}

	public String receivePGPMessage(PGPMessage pGPMessage) {
		this.receiveAuthMessage(pGPMessage.getAuth());
		return this.receiveConfMessage(pGPMessage.getConf());
	}

	public PublicKey getPubKey() {
		return this.publicKey;
	}
}
